﻿//----------------------------------------------------------------
// <copyright file="TheService.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//----------------------------------------------------------------

using System;
using System.Globalization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.ServiceProcess;
using System.Threading;
using System.Timers;
using MptCodeLibrary;
using MptCodeLibrary.Configuration;
using MptCodeLibrary.Exceptions;
using MptCodeLibrary.TeamFoundation;
using MptCodeLibrary.WcfReceivers;
using Timer=System.Timers.Timer;

namespace MptParentChildService
{
    public partial class TheService : ServiceBase
    {
        private ServiceHost workItemChangedServiceHost;
        private WebServiceHost rebuildGlobalListServiceHost;

        private readonly Timer setScheduleTimer = new Timer();
        private readonly Timer scheduleTimer = new Timer();
        private readonly Timer rollupTimer = new Timer();

        public TheService()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            Thread.Sleep(15*1000); // wait 15 seconds for debuggers to attach

            if (workItemChangedServiceHost != null)
                workItemChangedServiceHost.Close();

            workItemChangedServiceHost = new ServiceHost(typeof(WorkItemChangedReceiver));
            workItemChangedServiceHost.Open();
            
            if (rebuildGlobalListServiceHost != null)
                rebuildGlobalListServiceHost.Close();

            rebuildGlobalListServiceHost = new WebServiceHost(typeof (MptParentChildReceiver));
            rebuildGlobalListServiceHost.Open();

            MptInitializer mptInitializer = new MptInitializer(new MptConfiguration(), new TeamFoundationFacade());

            mptInitializer.SubscribeToEvents(workItemChangedServiceHost.BaseAddresses[0].AbsoluteUri);
            
            // create a time to fire off an 1 am to rebuild the global lists
            setScheduleTimer.Interval = MilliSecondsTill1am;

            setScheduleTimer.Elapsed += (OnSetStartTime);
            setScheduleTimer.Enabled = true;

            rollupTimer.Interval = TimeSpan.FromTicks(TimeSpan.TicksPerHour*3).TotalMilliseconds;
            rollupTimer.Elapsed += (RollupChangedWorkItems);
            rollupTimer.Enabled = true;
        }

        protected override void OnStop()
        {
            if (rebuildGlobalListServiceHost != null)
            {
                rebuildGlobalListServiceHost.Close();
                rebuildGlobalListServiceHost = null;
            }

            if (workItemChangedServiceHost != null)
            {
                workItemChangedServiceHost.Close();
                workItemChangedServiceHost = null;
            }

            if (setScheduleTimer.Enabled)
            {
                setScheduleTimer.Enabled = false;
                setScheduleTimer.Close();
            }

            if (scheduleTimer.Enabled)
            {
                scheduleTimer.Enabled = false;
                scheduleTimer.Close();
            }

            if (rollupTimer.Enabled)
            {
                rollupTimer.Enabled = false;
                rollupTimer.Close();

            }
        }

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            if (disposing && rebuildGlobalListServiceHost != null)
            {
                rebuildGlobalListServiceHost.Close();
            }
            
            base.Dispose(disposing);
        }

        /// <summary>
        /// The math is the number of milliseconds in a day - number of milliseconds so far today + the number of milliseconds 
        /// that are from midnight to 1 am
        /// </summary>
        private static double MilliSecondsTill1am
        {
            get
            {
                Double milliSecondsPerDay = TimeSpan.FromTicks(TimeSpan.TicksPerDay).TotalMilliseconds;
                Double milliSecondsPerHour = TimeSpan.FromTicks(TimeSpan.TicksPerHour).TotalMilliseconds;

                Double milliSecondsAsOfBegginningOfDay =
                    TimeSpan.FromTicks((new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day)).Ticks).
                        TotalMilliseconds;

                Double milliSecondsAsOfNow = TimeSpan.FromTicks(DateTime.Now.Ticks).TotalMilliseconds;

                return (milliSecondsPerDay -
                        (milliSecondsAsOfNow - milliSecondsAsOfBegginningOfDay) +
                        milliSecondsPerHour);
            }
        }

        private void OnSetStartTime(object source, ElapsedEventArgs e)
        {
            // close the schedule timer
            setScheduleTimer.Enabled = false;
            setScheduleTimer.Close();

            // setup the 24 hour timer to handle the rebuild
            scheduleTimer.Elapsed += (OnRebuildList);
            scheduleTimer.Interval = TimeSpan.FromTicks(TimeSpan.TicksPerDay).TotalMilliseconds;
            scheduleTimer.Enabled = true;

            // be sure to do the rebuild at the first 1am...
            RebuildGlobalList();
        }

        private static void OnRebuildList(object source, ElapsedEventArgs e)
        {
            RebuildGlobalList();
        }

        private static void RebuildGlobalList()
        {
            MptEventLogger.WriteTrace(string.Format(CultureInfo.InvariantCulture,
                                                    "Rebuilding this global lists at: {0} {1}",
                                                    DateTime.Now.ToShortDateString(), DateTime.Now.ToLongTimeString()));

            GlobalListBuilder globalListBuilder = new GlobalListBuilder(new MptConfiguration(),
                                                                        new TeamFoundationFacade());

            globalListBuilder.RebuildGlobalListsForProjects();

            MptEventLogger.WriteTrace("Finished with the schedule rebuild of the global list");

        }

        private static void RollupChangedWorkItems(object source, ElapsedEventArgs e)
        {
            MptEventLogger.WriteTrace(string.Format(CultureInfo.InvariantCulture,
                                        "Rolling up the changed workItems at: {0} {1}",
                                        DateTime.Now.ToShortDateString(), DateTime.Now.ToLongTimeString()));

            WorkItemRollup workItemRollup = new WorkItemRollup(new MptConfiguration());
            int returnValue = workItemRollup.IncrementalProcess();

            if (returnValue > 0)
                MptEventLogger.WriteError(
                    @"Finished with the schedule rollup of changed work items. There were errors with the rollup.  
                        Check the event viewer for more information");
            else
                MptEventLogger.WriteTrace("Finished with the schedule rollup of changed work items");
        }
    }
}
